package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.srb.common.exception.Assert;
import com.atguigu.srb.common.exception.SrbException;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.common.result.Result;
import com.atguigu.srb.common.util.*;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.pojo.entity.UserAccount;
import com.atguigu.srb.core.pojo.entity.UserBind;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.entity.UserLoginRecord;
import com.atguigu.srb.core.pojo.entity.vo.LoginVO;
import com.atguigu.srb.core.pojo.entity.vo.RegisterVO;
import com.atguigu.srb.core.pojo.entity.vo.UserIndexVO;
import com.atguigu.srb.core.pojo.entity.vo.UserInfoSearchVo;
import com.atguigu.srb.core.service.UserAccountService;
import com.atguigu.srb.core.service.UserBindService;
import com.atguigu.srb.core.service.UserInfoService;
import com.atguigu.srb.core.service.UserLoginRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 用户基本信息 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-03-25
 */
@Service
@Slf4j
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    UserLoginRecordService userLoginRecordService;

    @Resource
    UserBindService userBindService;

    @Resource
    UserAccountService userAccountService;

    @Override
    public void saveUser(RegisterVO registerVo, Integer type) {
        //1.检测注册参数
        Integer userType = registerVo.getUserType();
        String code = registerVo.getCode();
        String password = registerVo.getPassword();
        String mobile = registerVo.getMobile();
        Assert.assertNotTrue(type==null ||
                StringUtils.isEmpty(code) ||
                StringUtils.isEmpty(password) ||
                StringUtils.isEmpty(mobile),
                ResponseEnum.PARAM_NULL_ERROR);
//        //对手机号进行格式校验
//        Assert.assertTrue(RegexValidateUtils.checkCellphone(mobile), ResponseEnum.MOBILE_ERROR);
        //2.校验验证码
        /*
        "key->" + "sms:code:" + type + ":" + mobile + "; value->" + code
        */
        String redisCodeKey = "sms:code:" + type + ":" + mobile;
        String redisCodeValue = stringRedisTemplate.opsForValue().get(redisCodeKey);
        Assert.assertTrue(redisCodeValue.equals(code), ResponseEnum.CODE_ERROR);
        //删除用过的验证码
        stringRedisTemplate.delete(redisCodeKey);
//        //3.重复注册校验
//        Assert.assertTrue(this.count(Wrappers.lambdaQuery(UserInfo.class)
//                .eq(UserInfo::getMobile, mobile))==0, ResponseEnum.MOBILE_EXIST_ERROR);
        //4.密码加密
        String salt = RandomUtils.getSixBitRandom();
        String pwd = MD5.encrypt(password);
        String saltPwd = MD5.encrypt(pwd + salt);
        UserInfo userInfo = new UserInfo();
        userInfo.setUserType(userType);
        userInfo.setHeadImg("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        userInfo.setMobile(mobile);
        userInfo.setNickName("旅客" + "_" + UUID.randomUUID().toString().substring(0,8));
        userInfo.setPassword(saltPwd);
        userInfo.setSalt(salt);
        userInfo.setIntegral(0); //用户积分
        //5.保存到数据库
        this.save(userInfo);
    }

    @Override
    public String login(LoginVO loginVo, HttpServletRequest request) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
        Integer userType = loginVo.getUserType();

        //对每个值进行控制判断
        Assert.assertNotTrue(StringUtils.isEmpty(mobile) ||
                StringUtils.isEmpty(password) ||
                null == userType, ResponseEnum.PARAM_NULL_ERROR);
        //从数据库查询当前用户
        UserInfo userInfo = this.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getMobile, mobile)
                .eq(UserInfo::getUserType, userType));
        //判断用户是否存在
        Assert.notNull(userInfo, ResponseEnum.LOGIN_ACCOUNT_NULL_ERROR);
        //对密码进行加盐比较
        String salt = userInfo.getSalt();
        String md5Pwd = MD5.encrypt(password);
        String curSaltPwd = MD5.encrypt(md5Pwd + salt);
        String saltPwd = userInfo.getPassword();
        Assert.assertTrue(curSaltPwd.equals(saltPwd), ResponseEnum.LOGIN_PASSWORD_ERROR);
        addLog(userInfo, request);
        //返回token，使用jwt生成
        return JwtUtils.createToken(userInfo.getId(), userInfo.getName());
    }

    @Override
    public Page<UserInfo> getUserList(Integer pageNum, Integer pageSize, UserInfoSearchVo userInfoSearchVo) {
        Page<UserInfo> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        Integer status = userInfoSearchVo.getStatus();
        Integer userType = userInfoSearchVo.getUserType();
        String mobile = userInfoSearchVo.getMobile();
        if (userType!=null){
            wrapper.eq(UserInfo::getUserType, userType);
        }
        if (status!=null){
            wrapper.eq(UserInfo::getStatus, status);
        }
        if (mobile!=null){
            wrapper.like(UserInfo::getMobile, mobile);
        }
        this.page(page, wrapper);
        return page;
    }

    @Override
    public void updateStatus(String userId, Integer status) {
        UserInfo userInfo = new UserInfo();
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(userId) && this.getOne(wrapper.eq(UserInfo::getId, userId))!=null){
            userInfo.setId(userId);
            userInfo.setStatus(status);
            this.updateById(userInfo);
        }
    }

    @Async
    @Override
    public void addLog(UserInfo userInfo, HttpServletRequest request) {
        //登陆成功，保存登录日志
        UserLoginRecord log = new UserLoginRecord();
        log.setUserId(Long.valueOf(userInfo.getId()));
        log.setIp(IpUtils.getIpAddressAtService(request));
        log.setLoginType(2);
        userLoginRecordService.save(log);
    }

    @Override
    public Boolean isBindMobile(String token) {
        String userId = JwtUtils.getUserId(token);
        UserInfo user = this.getById(userId);
        return StringUtils.isNotEmpty(user.getMobile());
    }

    @Override
    public Boolean isUsed(String mobile) {
        UserInfo user = this.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getMobile, mobile));
        return user!=null;
    }

    @Override
    public void bindMobile(String token, RegisterVO registerVO) {
        String userId = JwtUtils.getUserId(token);
        try {
            //对手机号的格式进行验证
            Assert.assertTrue(RegexValidateUtils.checkCellphone(registerVO.getMobile()), ResponseEnum.MOBILE_ERROR);
            //将vo中的数据对微信用户进行绑定
            UserInfo userInfo = new UserInfo();
            userInfo.setId(userId);
            userInfo.setUserType(registerVO.getUserType());
            userInfo.setMobile(registerVO.getMobile());
            this.updateById(userInfo);
        } catch (Exception e) {
            throw new SrbException(ResponseEnum.MOBILE_EXIST_ERROR);
        }
    }

    @Override
    public UserIndexVO getUserIndexVo(String token) {
        String userId = JwtUtils.getUserId(token);

        return baseMapper.selectUserIndexVoByUserId(userId);
    }

    @Override
    @Transactional
    public String hfbNotify(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        Map<String, Object> params = RequestHelper.switchMap(parameterMap);
        //判断是否绑定成功
        //1.校验签名
        boolean signEquals = RequestHelper.isSignEquals(params);
        if (!signEquals){
            log.error("签名校验失败：{}", JSON.toJSONString(params));
            return "fail";
        }

        //2.判断返回值的code
        String resultCode = params.get("resultCode").toString();
        if (!"0001".equals(resultCode)){
            log.error("绑定失败：{}", JSON.toJSONString(resultCode));
            return "fail";
        }

        //给agentUserId对应用户 绑定bindCode到数据库中
        String agentUserId = params.get("agentUserId").toString(); //登录hfb的srb用户id
        String bindCode = params.get("bindCode").toString();
        //更新数据库
        UserBind userBind = userBindService.getOne(Wrappers.lambdaQuery(UserBind.class)
                .eq(UserBind::getUserId, agentUserId));
        userBind.setStatus(1);//1，绑定成功
        userBind.setBindCode(bindCode);
        userBindService.updateById(userBind);

        //更新用户表中的绑定信息
        UserInfo userInfo = this.getById(agentUserId);
        userInfo.setIdCard(userBind.getIdCard());
        userInfo.setBindStatus(1);
        userInfo.setName(userBind.getName());
        userInfo.setBindCode(bindCode);
        this.updateById(userInfo);
        System.out.println(agentUserId + " , " + bindCode);
        //为绑定hfb成功的会员开通个人账户
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(Long.valueOf(userInfo.getId()));
        userAccount.setAmount(new BigDecimal(0));
        userAccount.setFreezeAmount(new BigDecimal(0));
        userAccountService.save(userAccount);
        return "success";
    }
}